home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / mg / src.lzh / amiga / menustack.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  10KB  |  378 lines

  1. /*
  2.  * Simple menu package.  Needs lotsa work to handle some cases.
  3.  * 
  4.  * Copyright 1985 Louis A. Mamakos Software & Stuff 14813 Ashford Place Laurel,
  5.  * MD  20707
  6.  * 
  7.  * For non-commerical use only.  This program, or any modifications, may not be
  8.  * sold or incorporated into any product without prior permission from the
  9.  * author.
  10.  * 
  11.  * Modified by mwm to handle "stacking" menus. NB - adding item to a menu that's
  12.  * been "popped" back to doesn't work, and probably never will. Modified
  13.  * again by MPK to allow subitems again (non-stacking), and fix bug when
  14.  * visiting files not in last menu.
  15.  * 
  16.  * Modified once again by MPK to avoid calling strsave() if desired.  This is
  17.  * controlled by the newly-added last parameter to *_Add(), which indicates
  18.  * whether the menu name should be saved off by strsave(). I suppose *not*
  19.  * saving strings might break on a system where MEMF_PUBLIC meant something,
  20.  * but I think that's far in the future...
  21.  */
  22.  
  23. #include "do_menu.h"
  24. #ifdef    DO_MENU
  25.  
  26. #undef    LATTICE
  27. #undef    MANX
  28. #undef AZTEC
  29. #include "compiler.h"
  30.  
  31. #include <exec/types.h>
  32. #include <exec/nodes.h>
  33. #include <exec/lists.h>
  34. #include <exec/ports.h>
  35. #include <exec/devices.h>
  36. #include <exec/memory.h>
  37. #include <hardware/blit.h>
  38. #include <graphics/copper.h>
  39. #include <graphics/regions.h>
  40. #include <graphics/rastport.h>
  41. #include <graphics/gfxbase.h>
  42. #include <graphics/gels.h>
  43. #include <intuition/intuition.h>
  44. #ifdef LATTICE
  45. #include <proto/all.h>
  46. #else
  47. #include <functions.h>
  48. #endif
  49.  
  50. #undef TRUE
  51. #undef FALSE
  52. #include "def.h"
  53.  
  54. #ifdef ANSI
  55. #include <string.h>
  56. #endif
  57.  
  58. #define MNUM(menu,item,sub) (SHIFTMENU(menu)|SHIFTITEM(item)|SHIFTSUB(sub))
  59. #define    Menu_Clear    DisposeMenus    /* For ttyio.c     */
  60.  
  61. struct Mem_Node {
  62.     struct Node     mn_Node;
  63.     struct Remember *mn_Memory;
  64.     struct Menu    *mn_Menu;
  65. }              *Top;
  66.  
  67. extern struct Screen WBInfo;    /* For Screen width & Height     */
  68. #define SCREENHEIGHT    (WBInfo . Height)
  69. #define SCREENWIDTH    (WBInfo . Width)
  70.  
  71. static struct List Memory;
  72. static int      Cur_Menu, Cur_MenuItem, Cur_SubItem;
  73. static struct Menu *LastMenu;
  74. static struct MenuItem *LastMenuItem, *LastSubItem;
  75.  
  76. struct Menu    *AutoMenu;    /* menu struct being dynamically built */
  77.  
  78. #ifdef    MANX
  79. char           *strsave();    /* Save a string in the remember list */
  80. #else
  81. #define strsave(s) strdup(s)
  82. #ifdef AZTEC
  83. char *strdup PROTO((char *));
  84. #endif
  85. #endif
  86.  
  87. VOID
  88. Menu_Init()
  89. {
  90.     Memory.lh_Head = (struct Node *) & (Memory.lh_Tail);
  91.     Memory.lh_TailPred = (struct Node *) & (Memory.lh_Head);
  92.     Memory.lh_Tail = NULL;
  93.     Memory.lh_Type = NT_MEMORY;
  94.     Top = NULL;
  95.     Cur_Menu = Cur_MenuItem = Cur_SubItem = -1;
  96.     AutoMenu = LastMenu = NULL;    /* no menu chain yet */
  97.     LastMenuItem = LastSubItem = NULL;
  98. }
  99.  
  100. VOID
  101. Menu_Clear()
  102. {
  103.  
  104.     while ((Top = (struct Mem_Node *) RemHead(&Memory)) != NULL) {
  105.         FreeRemember(&(Top->mn_Memory), (LONG) TRUE);
  106.         FreeMem(Top, (LONG) sizeof(struct Mem_Node));
  107.     }
  108.     Menu_Init();        /* Just for safeties sake */
  109. }
  110.  
  111. VOID
  112. Menu_Pop()
  113. {
  114.  
  115.     if ((Top = (struct Mem_Node *) RemHead(&Memory)) == NULL)
  116.         return;
  117.     FreeRemember(&(Top->mn_Memory), (LONG) TRUE);
  118.     FreeMem(Top, (LONG) sizeof(struct Mem_Node));
  119.     /* Now, set Top back to the real list head */
  120.     Top = (struct Mem_Node *) Memory.lh_Head;
  121.     LastMenu = Top->mn_Menu;
  122.     LastMenu->NextMenu = NULL;    /* Tie off the menu list */
  123.     LastMenuItem = NULL;    /* Wrong, but you can't add items here anyway */
  124.     LastSubItem = NULL;    /* ditto                      */
  125.     Cur_Menu--;
  126. }
  127.  
  128. /*
  129.  * Add a MENU item.  Args are the text of the menu item, and an enable flag.
  130.  * Returns an Intuition type menu number, with the MenuItem and Menu SubItem
  131.  * being NOITEM and NOSUB.  The MENUITEM part is valid.
  132.  */
  133. /* dummy Intuitext used to calculate length of menu names */
  134. static struct IntuiText itd = {
  135.     AUTOFRONTPEN, AUTOBACKPEN, JAM2, 1, 1, NULL, NULL, NULL
  136. };
  137.  
  138. int
  139. Menu_Add(name, enabled, saveit)
  140.     char           *name;
  141.     int             enabled;
  142.     int             saveit;
  143. {
  144.     register struct Menu *m;
  145.  
  146.     if (!name)
  147.         return 0;
  148.     if ((Top = (struct Mem_Node *) AllocMem(
  149.                         (LONG) sizeof(struct Mem_Node), (LONG) MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  150.         return 0;
  151.     Top->mn_Node.ln_Type = NT_MEMORY;
  152.  
  153.     if ((m = (struct Menu *) AllocRemember(&(Top->mn_Memory),
  154.          (LONG) sizeof(struct Menu), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  155.         return 0;
  156.     Top->mn_Menu = m;
  157.  
  158.     if (LastMenu == NULL)
  159.         AutoMenu = m;    /* first menu on list */
  160.     else
  161.         LastMenu->NextMenu = m;    /* link it in */
  162.  
  163.     LastMenuItem = NULL;    /* end of previous MenuItem list */
  164.     LastSubItem = NULL;
  165.     Cur_MenuItem = Cur_SubItem = -1;    /* reset item numbers */
  166.     if (LastMenu == NULL)
  167.         m->LeftEdge = 0;
  168.     else
  169.         m->LeftEdge = LastMenu->LeftEdge + LastMenu->Width;
  170.     m->TopEdge = 0;
  171.     itd.IText = (UBYTE *) name;
  172.     m->Width = IntuiTextLength(&itd);
  173.     Top->mn_Node.ln_Name = m->MenuName = saveit ? strsave(name) : name;
  174.     m->Height = 0;
  175.     m->Flags = enabled ? MENUENABLED : 0;
  176.     m->FirstItem = NULL;
  177.     LastMenu = m;
  178.  
  179.     AddHead(&Memory, (struct Node *) Top);
  180.     return MNUM(++Cur_Menu, NOITEM, NOSUB);
  181. }
  182.  
  183. /*
  184.  * Add a menu item to the current MENU.  Note that Add_Menu *must* be called
  185.  * before this function.
  186.  */
  187. int
  188. Menu_Item_Add(name, flags, mux, ch, saveit)
  189.     char           *name;    /* name of menu item */
  190.     unsigned int    flags;
  191.     LONG            mux;    /* mutual exclusion mask */
  192.     int        ch;    /* command sequence character, if COMMSEQ */
  193.     int             saveit;    /* save name using strsave? */
  194. {
  195.     register struct MenuItem *m, *n;
  196.     register struct IntuiText *it;
  197.  
  198.     if (!name)
  199.         return 0;
  200.     flags &= CHECKIT | CHECKED | COMMSEQ | MENUTOGGLE | ITEMENABLED | HIGHCOMP | HIGHBOX;
  201.     if (LastMenu == NULL)
  202.         return MNUM(NOMENU, NOITEM, NOSUB);
  203.  
  204.     if ((m = (struct MenuItem *) AllocRemember(&(Top->mn_Memory),
  205.                            (LONG) sizeof(struct MenuItem), (LONG) MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  206.         return MNUM(NOMENU, NOITEM, NOSUB);
  207.  
  208.     LastSubItem = NULL;    /* terminate possible list of subitems */
  209.     Cur_SubItem = -1;
  210.     if (LastMenuItem == NULL)
  211.         LastMenu->FirstItem = m;
  212.     else
  213.         LastMenuItem->NextItem = m;
  214.     m->Flags = flags | ITEMTEXT;
  215.     /*
  216.      * Check for highlight mode:  if none selected, use HIGHCOMP
  217.      */
  218.     if ((m->Flags & (HIGHCOMP | HIGHBOX)) == 0)
  219.         m->Flags |= HIGHCOMP;
  220.     m->Command = ch;
  221.     m->MutualExclude = mux;
  222.     m->SubItem = NULL;
  223.     m->ItemFill = (APTR) AllocRemember(&(Top->mn_Memory),
  224.       (LONG) sizeof(struct IntuiText), (LONG) MEMF_PUBLIC | MEMF_CLEAR);
  225.     it = (struct IntuiText *) m->ItemFill;
  226.     it->FrontPen = AUTOFRONTPEN;
  227.     it->BackPen = AUTOBACKPEN;
  228.     it->DrawMode = JAM2;
  229.     if (flags & CHECKIT)
  230.         it->LeftEdge = CHECKWIDTH + 1;
  231.     else
  232.         it->LeftEdge = 1;
  233.     it->TopEdge = 1;
  234.     it->ITextFont = NULL;    /* default font */
  235.     it->IText = (UBYTE *) (saveit ? strsave(name) : name);
  236.     it->NextText = NULL;
  237.     if (LastMenuItem == NULL) {
  238.         m->TopEdge = 2;
  239.         m->LeftEdge = 0;
  240.     } else if (LastMenuItem->TopEdge + 40 > SCREENHEIGHT) {
  241.         m->TopEdge = 2;
  242.         m->LeftEdge = LastMenuItem->LeftEdge + LastMenuItem->Width + 12;
  243.         if (m->LeftEdge > SCREENWIDTH) {
  244.             LastMenuItem->NextItem = NULL;
  245.             LastMenuItem->Flags &= ~ITEMENABLED;
  246.             return MNUM(NOMENU, NOITEM, NOSUB);
  247.         }
  248.     } else {
  249.         m->TopEdge = LastMenuItem->TopEdge + 10;
  250.         m->LeftEdge = LastMenuItem->LeftEdge;
  251.     }
  252.     m->Width = 0;
  253.     if (flags & CHECKIT)
  254.         m->Width += CHECKWIDTH;
  255.     if (flags & COMMSEQ)
  256.         m->Width += COMMWIDTH + 20;
  257.     m->Width += IntuiTextLength((struct IntuiText *) m->ItemFill);
  258.     m->Height = 10;
  259.     /*
  260.      * Check last menu item's width to see if it is larger than this
  261.      * item's.  If new item is larger, then update width of all other
  262.      * items.
  263.      */
  264.     if (LastMenuItem) {
  265.         if (LastMenuItem->Width > m->Width)
  266.             m->Width = LastMenuItem->Width;
  267.         else {
  268.             register short  delta = m->Width - LastMenuItem->Width;
  269.  
  270.             for (n = LastMenu->FirstItem; n != m; n = n->NextItem) {
  271.                 n->Width = m->Width;
  272.                 if (n->LeftEdge > 0)
  273.                     n->LeftEdge += delta;
  274.             }
  275.             if (m->LeftEdge > 0)
  276.                 m->LeftEdge += delta;
  277.         }
  278.     }
  279.     LastMenuItem = m;
  280.     return MNUM(Cur_Menu, ++Cur_MenuItem, NOSUB);
  281. }
  282.  
  283. int
  284. Menu_SubItem_Add(name, flags, mux, ch, saveit)
  285.     char           *name;
  286.     unsigned int    flags;
  287.     LONG            mux;
  288.     int        ch;
  289.     int             saveit;
  290. {
  291.     register struct MenuItem *m, *n;
  292.     register struct IntuiText *it;
  293.  
  294.     if (!name)
  295.         return 0;
  296.     flags &= CHECKIT | CHECKED | COMMSEQ | MENUTOGGLE | ITEMENABLED | HIGHCOMP | HIGHBOX;
  297.     if (LastMenuItem == NULL)
  298.         return MNUM(NOMENU, NOITEM, NOSUB);
  299.  
  300.     if ((m = (struct MenuItem *) AllocRemember(&(Top->mn_Memory),
  301.                            (LONG) sizeof(struct MenuItem), (LONG) MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  302.         return MNUM(NOMENU, NOITEM, NOSUB);
  303.  
  304.     if (LastSubItem == NULL)
  305.         LastMenuItem->SubItem = m;
  306.     else
  307.         LastSubItem->NextItem = m;
  308.     m->Flags = flags | ITEMTEXT;
  309.     /*
  310.      * check for highlight mode.  If none selected, use HIGHCOMP
  311.      */
  312.     if ((m->Flags & (HIGHCOMP | HIGHBOX)) == 0)
  313.         m->Flags |= HIGHCOMP;
  314.     m->Command = ch;
  315.     m->MutualExclude = mux;
  316.     m->SubItem = NULL;
  317.     m->ItemFill = (APTR) AllocRemember(&(Top->mn_Memory),
  318.       (LONG) sizeof(struct IntuiText), (LONG) MEMF_PUBLIC | MEMF_CLEAR);
  319.     it = (struct IntuiText *) m->ItemFill;
  320.     it->FrontPen = AUTOFRONTPEN;
  321.     it->BackPen = AUTOBACKPEN;
  322.     it->DrawMode = JAM2;
  323.     if (flags & CHECKIT)
  324.         it->LeftEdge = CHECKWIDTH + 1;
  325.     else
  326.         it->LeftEdge = 1;
  327.     it->TopEdge = 1;
  328.     it->ITextFont = NULL;    /* default font */
  329.     it->IText = (UBYTE *) (saveit ? strsave(name) : name);
  330.     it->NextText = NULL;
  331.     m->LeftEdge = LastMenuItem->Width + 10;
  332.     m->Width = 0;
  333.     if (LastSubItem == NULL)
  334.         m->TopEdge = 1;
  335.     else
  336.         m->TopEdge = LastSubItem->TopEdge + 10;
  337.     if (flags & CHECKIT)
  338.         m->Width += CHECKWIDTH;
  339.     if (flags & COMMSEQ)
  340.         m->Width += COMMWIDTH + 20;
  341.     m->Width += IntuiTextLength((struct IntuiText *) m->ItemFill);
  342.     m->Height = 10;
  343.     /*
  344.      * Check last menu item's width to see if it is larger than this
  345.      * item's.  If new item is larger, then update width of all other
  346.      * items.
  347.      */
  348.     if (LastSubItem) {
  349.         if (LastSubItem->Width > m->Width)
  350.             m->Width = LastSubItem->Width;
  351.         else
  352.             for (n = LastMenuItem->SubItem; n != m; n = n->NextItem)
  353.                 n->Width = m->Width;
  354.     }
  355.     LastSubItem = m;
  356.     return MNUM(Cur_Menu, Cur_MenuItem, ++Cur_SubItem);
  357. }
  358.  
  359. #ifdef    MANX
  360. char           *
  361. strsave(string)
  362.     char           *string;
  363. {
  364.     char           *out;
  365.  
  366.     out = (char *) AllocRemember(&(Top->mn_Memory), (LONG) (strlen(string) + 1),
  367.                      (LONG) MEMF_PUBLIC);
  368.     if (out == NULL)
  369.         return NULL;
  370.  
  371.     (void) strcpy(out, string);
  372.     return out;
  373. }
  374. #endif
  375. #else
  376. #include "nullfile.h"
  377. #endif
  378.